#include "stdafx.h"
#include "Keyboard.h"

namespace Reign
{namespace Input
{namespace DI
{
	#pragma region Properties
	Button^ Keyboard::Key(int index) {return button[index];}
	Button^ Keyboard::A::get() {return button[DIK_A];}
	Button^ Keyboard::B::get() {return button[DIK_B];}
	Button^ Keyboard::C::get() {return button[DIK_C];}
	Button^ Keyboard::D::get() {return button[DIK_D];}
	Button^ Keyboard::E::get() {return button[DIK_E];}
	Button^ Keyboard::F::get() {return button[DIK_F];}
	Button^ Keyboard::G::get() {return button[DIK_G];}
	Button^ Keyboard::H::get() {return button[DIK_H];}
	Button^ Keyboard::I::get() {return button[DIK_I];}
	Button^ Keyboard::J::get() {return button[DIK_J];}
	Button^ Keyboard::K::get() {return button[DIK_K];}
	Button^ Keyboard::L::get() {return button[DIK_L];}
	Button^ Keyboard::M::get() {return button[DIK_M];}
	Button^ Keyboard::N::get() {return button[DIK_N];}
	Button^ Keyboard::O::get() {return button[DIK_O];}
	Button^ Keyboard::P::get() {return button[DIK_P];}
	Button^ Keyboard::Q::get() {return button[DIK_Q];}
	Button^ Keyboard::R::get() {return button[DIK_R];}
	Button^ Keyboard::S::get() {return button[DIK_S];}
	Button^ Keyboard::T::get() {return button[DIK_T];}
	Button^ Keyboard::U::get() {return button[DIK_U];}
	Button^ Keyboard::V::get() {return button[DIK_V];}
	Button^ Keyboard::W::get() {return button[DIK_W];}
	Button^ Keyboard::X::get() {return button[DIK_X];}
	Button^ Keyboard::Y::get() {return button[DIK_Y];}
	Button^ Keyboard::Z::get() {return button[DIK_Z];}
	Button^ Keyboard::D0::get() {return button[DIK_0];}
	Button^ Keyboard::D1::get() {return button[DIK_1];}
	Button^ Keyboard::D2::get() {return button[DIK_2];}
	Button^ Keyboard::D3::get() {return button[DIK_3];}
	Button^ Keyboard::D4::get() {return button[DIK_4];}
	Button^ Keyboard::D5::get() {return button[DIK_5];}
	Button^ Keyboard::D6::get() {return button[DIK_6];}
	Button^ Keyboard::D7::get() {return button[DIK_7];}
	Button^ Keyboard::D8::get() {return button[DIK_8];}
	Button^ Keyboard::D9::get() {return button[DIK_9];}
	Button^ Keyboard::F1::get() {return button[DIK_F1];}
	Button^ Keyboard::F2::get() {return button[DIK_F2];}
	Button^ Keyboard::F3::get() {return button[DIK_F3];}
	Button^ Keyboard::F4::get() {return button[DIK_F4];}
	Button^ Keyboard::F5::get() {return button[DIK_F5];}
	Button^ Keyboard::F6::get() {return button[DIK_F6];}
	Button^ Keyboard::F7::get() {return button[DIK_F7];}
	Button^ Keyboard::F8::get() {return button[DIK_F8];}
	Button^ Keyboard::F9::get() {return button[DIK_F9];}
	Button^ Keyboard::F10::get() {return button[DIK_F10];}
	Button^ Keyboard::F11::get() {return button[DIK_F11];}
	Button^ Keyboard::F12::get() {return button[DIK_F12];}
	Button^ Keyboard::F13::get() {return button[DIK_F13];}
	Button^ Keyboard::F14::get() {return button[DIK_F14];}
	Button^ Keyboard::F15::get() {return button[DIK_F15];}
	Button^ Keyboard::ArrowLeft::get() {return button[DIK_LEFT];}
	Button^ Keyboard::ArrowRight::get() {return button[DIK_RIGHT];}
	Button^ Keyboard::ArrowDown::get() {return button[DIK_DOWN];}
	Button^ Keyboard::ArrowUp::get() {return button[DIK_UP];}
	Button^ Keyboard::Space::get() {return button[DIK_SPACE];}
	Button^ Keyboard::Esc::get() {return button[DIK_ESCAPE];}
	Button^ Keyboard::Minus::get() {return button[DIK_MINUS];}
	Button^ Keyboard::Equal::get() {return button[DIK_EQUALS];}
	Button^ Keyboard::Backspace::get() {return button[DIK_BACK];}
	Button^ Keyboard::Tab::get() {return button[DIK_TAB];}
	Button^ Keyboard::BracketLeft::get() {return button[DIK_LBRACKET];}
	Button^ Keyboard::BracketRight::get() {return button[DIK_RBRACKET];}
	Button^ Keyboard::Return::get() {return button[DIK_RETURN];}
	Button^ Keyboard::ControlLeft::get() {return button[DIK_LCONTROL];}
	Button^ Keyboard::ControlRight::get() {return button[DIK_RCONTROL];}
	Button^ Keyboard::SemiColon::get() {return button[DIK_SEMICOLON];}
	Button^ Keyboard::Apostrophe::get() {return button[DIK_APOSTROPHE];}
	Button^ Keyboard::Grave::get() {return button[DIK_GRAVE];}
	Button^ Keyboard::ShiftLeft::get() {return button[DIK_LSHIFT];}
	Button^ Keyboard::ShiftRight::get() {return button[DIK_RSHIFT];}
	Button^ Keyboard::Comma::get() {return button[DIK_COMMA];}
	Button^ Keyboard::Period::get() {return button[DIK_PERIOD];}
	Button^ Keyboard::SlashBack::get() {return button[DIK_BACKSLASH];}
	Button^ Keyboard::SlashForward::get() {return button[DIK_SLASH];}
	Button^ Keyboard::AltLeft::get() {return button[DIK_LMENU];}
	Button^ Keyboard::AltRight::get() {return button[DIK_RMENU];}
	Button^ Keyboard::WindowsKeyLeft::get() {return button[DIK_LWIN];}
	Button^ Keyboard::WindowsKeyRight::get() {return button[DIK_RWIN];}
	Button^ Keyboard::Capital::get() {return button[DIK_CAPITAL];}
	Button^ Keyboard::NumLock::get() {return button[DIK_NUMLOCK];}
	Button^ Keyboard::Scroll::get() {return button[DIK_SCROLL];}
	Button^ Keyboard::Decimal::get() {return button[DIK_DECIMAL];}
	Button^ Keyboard::OEM_102::get() {return button[DIK_OEM_102];}
	Button^ Keyboard::KANA::get() {return button[DIK_KANA];}
	Button^ Keyboard::ABNT_C1::get() {return button[DIK_ABNT_C1];}
	Button^ Keyboard::Convert::get() {return button[DIK_CONVERT];}
	Button^ Keyboard::NoConvert::get() {return button[DIK_NOCONVERT];}
	Button^ Keyboard::YEN::get() {return button[DIK_YEN];}
	Button^ Keyboard::ABNT_C2::get() {return button[DIK_ABNT_C2];}
	Button^ Keyboard::PrevTrack::get() {return button[DIK_PREVTRACK];}
	Button^ Keyboard::NextTrack::get() {return button[DIK_NEXTTRACK];}
	Button^ Keyboard::PlayPause::get() {return button[DIK_PLAYPAUSE];}
	Button^ Keyboard::Pause::get() {return button[DIK_PAUSE];}
	Button^ Keyboard::MediaStop::get() {return button[DIK_MEDIASTOP];}
	Button^ Keyboard::MediaSelect::get() {return button[DIK_MEDIASELECT];}
	Button^ Keyboard::VolumeDown::get() {return button[DIK_VOLUMEDOWN];}
	Button^ Keyboard::VolumeUp::get() {return button[DIK_VOLUMEUP];}
	Button^ Keyboard::Apps::get() {return button[DIK_APPS];}
	Button^ Keyboard::Power::get() {return button[DIK_POWER];}
	Button^ Keyboard::Sleep::get() {return button[DIK_SLEEP];}
	Button^ Keyboard::Wake::get() {return button[DIK_WAKE];}
	Button^ Keyboard::WebHome::get() {return button[DIK_WEBHOME];}
	Button^ Keyboard::WebSearch::get() {return button[DIK_WEBSEARCH];}
	Button^ Keyboard::WebFavorites::get() {return button[DIK_WEBFAVORITES];}
	Button^ Keyboard::WebRefresh::get() {return button[DIK_WEBREFRESH];}
	Button^ Keyboard::WebStop::get() {return button[DIK_WEBSTOP];}
	Button^ Keyboard::WebForward::get() {return button[DIK_WEBFORWARD];}
	Button^ Keyboard::WebBack::get() {return button[DIK_WEBBACK];}
	Button^ Keyboard::MyComputer::get() {return button[DIK_MYCOMPUTER];}
	Button^ Keyboard::Mail::get() {return button[DIK_MAIL];}
	Button^ Keyboard::Home::get() {return button[DIK_HOME];}
	Button^ Keyboard::End::get() {return button[DIK_END];}
	Button^ Keyboard::PageUp::get() {return button[DIK_PRIOR];}
	Button^ Keyboard::PageDown::get() {return button[DIK_NEXT];}
	Button^ Keyboard::Insert::get() {return button[DIK_INSERT];}
	Button^ Keyboard::Delete_NOTE_Dispose::get() {return button[DIK_DELETE];}
	Button^ Keyboard::NumPad0::get() {return button[DIK_NUMPAD0];}
	Button^ Keyboard::NumPad1::get() {return button[DIK_NUMPAD1];}
	Button^ Keyboard::NumPad2::get() {return button[DIK_NUMPAD2];}
	Button^ Keyboard::NumPad3::get() {return button[DIK_NUMPAD3];}
	Button^ Keyboard::NumPad4::get() {return button[DIK_NUMPAD4];}
	Button^ Keyboard::NumPad5::get() {return button[DIK_NUMPAD5];}
	Button^ Keyboard::NumPad6::get() {return button[DIK_NUMPAD6];}
	Button^ Keyboard::NumPad7::get() {return button[DIK_NUMPAD7];}
	Button^ Keyboard::NumPad8::get() {return button[DIK_NUMPAD8];}
	Button^ Keyboard::NumPad9::get() {return button[DIK_NUMPAD9];}
	Button^ Keyboard::NumPadEqual::get() {return button[DIK_NUMPADEQUALS];}
	Button^ Keyboard::NumPadEnter::get() {return button[DIK_NUMPADENTER];}
	Button^ Keyboard::NumPadComma::get() {return button[DIK_NUMPADCOMMA];}
	Button^ Keyboard::NumPadDevide::get() {return button[DIK_DIVIDE];}
	Button^ Keyboard::NumPadSubtract::get() {return button[DIK_SUBTRACT];}
	Button^ Keyboard::NumPadAdd::get() {return button[DIK_ADD];}
	Button^ Keyboard::NumPadMultiply::get() {return button[DIK_MULTIPLY];}
	Button^ Keyboard::AT::get() {return button[DIK_AT];}
	Button^ Keyboard::Colon::get() {return button[DIK_COLON];}
	Button^ Keyboard::Underline::get() {return button[DIK_UNDERLINE];}
	Button^ Keyboard::KANJI::get() {return button[DIK_KANJI];}
	Button^ Keyboard::Stop::get() {return button[DIK_STOP];}
	Button^ Keyboard::AX::get() {return button[DIK_AX];}
	Button^ Keyboard::Unlabeled::get() {return button[DIK_UNLABELED];}
	Button^ Keyboard::Mute::get() {return button[DIK_MUTE];}
	Button^ Keyboard::Calculator::get() {return button[DIK_CALCULATOR];}
	Button^ Keyboard::SYSRQ::get() {return button[DIK_SYSRQ];}
	#pragma endregion

	#pragma region Constructors
	Keyboard::Keyboard(DisposableI^ parent)
	: Disposable(parent)
	{
		null();
		try
		{
			input = parent->FindParentOrSelfWithException<Input^>();

			button = gcnew array<Button^>(256);
			for (int i = 0; i != 256; ++i)
			{
				button[i] = gcnew Button();
			}
			
			keys = new char[256];
			ZeroMemory(keys, sizeof(char)*256);

			IDirectInputDevice8* deviceTEMP;
			if (FAILED(input->Device->CreateDevice(GUID_SysKeyboard, &deviceTEMP, 0)))
			{
				device = 0;
				throw(gcnew string(L"Reign.Input.DI.Keyboard: Failed at pInput->Device()->CreateDevice"));
			}
			device = deviceTEMP;

			if (FAILED(device->SetDataFormat(&c_dfDIKeyboard))) throw(gcnew string(L"Reign.Input.DI.Keyboard: Failed at device->SetDataForma"));
			if (FAILED(device->SetCooperativeLevel((HWND)input->handle.ToPointer(), DISCL_NONEXCLUSIVE|DISCL_FOREGROUND))) throw(gcnew Exception("Reign.Input.DI.Keyboard: Failed at device->SetCooperativeLevel"));

			input->UpdateCallback += gcnew Input::UpdateCallbackFunc(this, &Keyboard::Update);
		}
		catch (Exception^ ex)
		{
			delete this;
			throw ex;
		}
	}

	Keyboard::~Keyboard()
	{
		disposeChilderen();
		if (device)
		{
			if (input) input->UpdateCallback -= gcnew Input::UpdateCallbackFunc(this, &Keyboard::Update);
			device->Unacquire();
			device->Release();
		}
		if (keys) delete keys;
		null();
	}

	void Keyboard::null()
	{
		device = 0;
		keys = 0;
		input = nullptr;
	}
	#pragma endregion
	
	#pragma region Methods
	void Keyboard::Update()
	{
		if (FAILED(device->Poll()))
		{
			while (device->Acquire() == DIERR_INPUTLOST);
		}
		
		device->GetDeviceState(sizeof(char)*256, keys);
		for (int i = 0; i != 256; ++i)
		{
			button[i]->Update(keys[i]);
		}
	}
	#pragma endregion
}
}
}